package com.lanchetech.user.service.impl;


import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.lanchetech.bean.dto.SignInCoinDTO;
import com.lanchetech.bean.request.LotteryOpportunityPageReq;
import com.lanchetech.bean.request.PageReq;
import com.lanchetech.bean.request.UserVoucherReq;
import com.lanchetech.bean.response.BargainEditResp;
import com.lanchetech.bean.response.BasePageResp;
import com.lanchetech.bean.response.BaseResp;
import com.lanchetech.bean.response.ResultData;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.*;
import com.lanchetech.common.enums.*;
import com.lanchetech.common.util.ReducePriceUtils;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.CommonFarmService;
import com.lanchetech.service.DaoService;
import com.lanchetech.service.HonorService;
import com.lanchetech.user.service.CommonService;
import com.lanchetech.user.service.MarketingService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MarketingServiceImpl implements MarketingService {

    @Autowired
    CouponMapper couponMapper;

    @Autowired
    UserCouponMapper userCouponMapper;

    @Autowired
    SignInMapper signInMapper;

    @Autowired
    WebConfigMapper webConfigMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    ExpFlowMapper expFlowMapper;

    @Autowired
    HonorService honorService;

    @Autowired
    CoinFlowMapper coinFlowMapper;

    @Autowired
    BargainActivityMapper bargainActivityMapper;

    @Autowired
    BargainSpuMapper bargainSpuMapper;

    @Autowired
    BargainSkuMapper bargainSkuMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    BargainRecordMapper bargainRecordMapper;

    @Autowired
    BargainDetailMapper bargainDetailMapper;

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    SkuMapper skuMapper;

    @Autowired
    UserVoucherMapper userVoucherMapper;

    @Autowired
    CommonFarmService commonFarmService;

    @Autowired
    FarmTaskMapper farmTaskMapper;

    @Autowired
    LotteryOpportunityMapper lotteryOpportunityMapper;

    @Override
    public ResultData<BasePageResp<Coupon>> getAllCouponPage(User user, PageReq req) {
        req.setStatus(ToggleEnum.ON.getStatus());
        req.setNow(new Date());

        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<Coupon> list = couponMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            // 如果用户已领取，就把status变成1
            if (user != null) {
                // 如果用户已经注册
                List<UserCoupon> userCouponList = userCouponMapper.findAllByUserIdAndCouponIds(user.getId(), list.stream().map(Coupon::getId).collect(Collectors.toList()));
                if (!CollectionUtils.isEmpty(userCouponList)) {
                    List<Long> couponIds = userCouponList.stream().map(UserCoupon::getCouponId).collect(Collectors.toList());
                    list.stream().forEach(item -> {
                        if (couponIds.contains(item.getId())) {
                            // 表示已经领取
                            item.setStatus(ToggleEnum.OFF.getStatus());
                        }
                    });
                }
            }
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public BaseResp selectCoupon(User user, Long id) {
        // 先判断优惠券是否可领取
        Date now = new Date();
        Coupon coupon = couponMapper.selectByPrimaryKey(id);
        if (DeletedEnum.DEFAULT.getStatus().equals(coupon.getDeleted())
                && ToggleEnum.ON.getStatus().equals(coupon.getStatus())
                && now.getTime() > coupon.getStartTime().getTime()
                && now.getTime() < coupon.getEndTime().getTime()
                && coupon.getStock() > 0
        ) {
            // 再判断是否已经领取
            UserCoupon userCoupon = userCouponMapper.findOneByUserIdAndCouponId(user.getId(), id);
            if (userCoupon == null) {
                userCouponMapper.insert(UserCoupon.builder()
                        .userId(user.getId())
                        .couponId(id)
                        .tenantId(coupon.getTenantId())
                        .status(UseEnum.NOT_USE.getStatus())
                        .useStartTime(coupon.getUseStartTime())
                        .useEndTime(coupon.getUseEndTime())
                        .createdAt(now)
                        .updatedAt(now)
                        .build());
                // 优惠券库存减1，已发放数量加1
                couponMapper.updateStockById(id);
            }
        } else {
            return new BaseResp(ResultCode.COUPON_CLOSE);
        }

        return new BaseResp();
    }

    @Override
    public ResultData<BigDecimal> getSignIn() {
        ResultData<BigDecimal> resultData = new ResultData<>();
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Date now = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
        Integer month = Integer.valueOf(sdf.format(now));
        sdf = new SimpleDateFormat("d");
        Integer day = Integer.valueOf(sdf.format(now));
        SignIn result = signInMapper.findOneByUserIdAndMonthAndDay(user.getId(), month, day);
        if (result == null) {
            // 签到
            signInMapper.insert(SignIn.builder()
                    .userId(user.getId())
                    .createdAt(now)
                    .month(month)
                    .day(day)
                    .build());

            // 加经验
            String signInCoin = webConfigMapper.findValueByName(WebConfigEnum.SIGN_IN_EXP.getConfig());
            SignInCoinDTO signInCoinDTO = JSON.parseObject(signInCoin, SignInCoinDTO.class);
            BigDecimal coin = signInCoinDTO.getOne();

            Integer count = signInMapper.countByUserIdAndMonth(user.getId(), month);
            if (count == 10) {
                coin = coin.add(signInCoinDTO.getTen());
            } else if (count == 20) {
                coin = coin.add(signInCoinDTO.getTwenty());
            }

            // 暂时不动等级
            user.setCoin(user.getCoin().add(coin));
            userMapper.updateCoinById(user.getCoin(), user.getId());

            // 创建积分使用记录
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd");
            coinFlowMapper.insert(CoinFlow.builder()
                    .userId(user.getId())
                    .amount(coin)
                    .tradeType(CoinFlowTradeTypeEnum.SIGN_IN.getTradeType())
                    .type(CoinFlowTradeTypeEnum.SIGN_IN.getType())
                    .coin(user.getCoin())
                    .relateId(Long.valueOf(sdf2.format(now)))
                    .remark("签到奖励收入")
                    .createdAt(new Date())
                    .build());

            //每日签到任务
            commonFarmService.checkTaskDone(user, FarmTaskKindEnum.SIGN_IN.getKind(), null, null);
            //累计签到任务
            commonFarmService.checkTaskDone(user, FarmTaskKindEnum.SIGN_IN_CUMULATIVE.getKind(), null, count.longValue());

            resultData.setValue(coin);
            return resultData;
        } else {
            resultData.setValue(BigDecimal.ZERO);
            resultData.setResultCode(ResultCode.SIGN_IN_TODAY);
            return resultData;
        }
    }

    @Override
    public ResultData<Boolean> isSignIn() {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Integer result = signInMapper.countTodaySignIn(user.getId());
        ResultData<Boolean> resultData = new ResultData<>();
        resultData.setValue(result > 0);
        return resultData;
    }

    @Override
    public ResultData<List<SignIn>> getMonthSignInRecord(Integer month) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return new ResultData<>(signInMapper.findAllByUserIdAndMonth(user.getId(), month));
    }

    @Override
    public ResultData<BasePageResp<BargainSpuItemVO>> getBargainPage(PageReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BargainSpuItemVO> list = bargainSpuMapper.findAllPageForUser(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Spu> spuHashMap = daoService.getSpuMap(list.stream().map(BargainSpuItemVO::getSpuId).collect(Collectors.toList()));

            List<BargainActivity> activityList = bargainActivityMapper.findAllByIds(list.stream().map(BargainSpuItemVO::getActivityId).collect(Collectors.toList()));
            List<BargainSku> bargainSkuList = bargainSkuMapper.findAllByActivityIds(list.stream().map(BargainSpuItemVO::getActivityId).collect(Collectors.toList()));

            Map<Long, BargainActivity> activityMap = new HashMap<>();
            activityList.stream().forEach(item -> activityMap.put(item.getId(), item));

            Map<Long, BargainSku> skuMap = new HashMap<>();
            bargainSkuList.stream().forEach(item -> skuMap.put(item.getActivityId(), item));

            list.stream().forEach(item -> {
                item.setMainImage(spuHashMap.get(item.getSpuId()).getMainImage());
                item.setSpuPrice(spuHashMap.get(item.getSpuId()).getMinPrice());
                item.setName(spuHashMap.get(item.getSpuId()).getName());
                item.setOriginalPrice(spuHashMap.get(item.getSpuId()).getOriginalPrice());
                item.setActivity(activityMap.get(item.getActivityId()));
                item.setBargainSku(skuMap.get(item.getActivityId()));
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BargainEditResp> getBargainDetail(Long id) {
        BargainEditResp resp = new BargainEditResp();
        resp.setActivity(bargainActivityMapper.selectByPrimaryKey(id));
        resp.setSpuList(bargainSpuMapper.findAllByActivityId(id));
        resp.setSkuList(bargainSkuMapper.findAllByActivityId(id));
        return new ResultData<>(resp);
    }

    @Override
    public ResultData<Long> createBargainRecord(BargainRecord req) {
        ResultData<Long> resultData = new ResultData();
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        BargainActivity bargainActivity = bargainActivityMapper.selectByPrimaryKey(req.getActivityId());
        BargainSpu bargainSpu = bargainSpuMapper.findOneByActivityId(req.getActivityId());

        // 统计已经参与的数量
        Long totalCount = bargainRecordMapper.sumByUserIdAndActivityId(user.getId(), req.getActivityId());

        if (totalCount != null && totalCount >= bargainSpu.getLimitCount() && !bargainSpu.getLimitCount().equals(0)) {
            resultData.setResultCode(ResultCode.MAX_BARGAIN);
            return resultData;
        }

        Date now = new Date();
        if (now.before(bargainActivity.getStartTime()) || now.after(bargainActivity.getEndTime())) {
            resultData.setResultCode(ResultCode.BARGAIN_NOT_IN_TIME);
            return resultData;
        }
        if (ToggleEnum.OFF.getStatus().equals(bargainActivity.getStatus())) {
            resultData.setResultCode(ResultCode.BARGAIN_OFF);
            return resultData;
        }

        req.setUserId(user.getId());
        req.setMaxHelperCount(bargainActivity.getHelperCount() * req.getCount());
        req.setMaxBargainAmount(bargainActivity.getBargainAmount().multiply(BigDecimal.valueOf(req.getCount())));
        req.setHelperCount(0);
        req.setBargainAmount(BigDecimal.ZERO);
        req.setStatus(ToggleEnum.OFF.getStatus());
        // 直接生成砍价分配金额
        List<Double> doubleList = ReducePriceUtils.splitReducePrice(req.getMaxBargainAmount().multiply(BigDecimal.valueOf(100)).intValue(), req.getMaxHelperCount());
        req.setFeature(JSON.toJSONString(doubleList));
        req.setCreatedAt(new Date());
        req.setUpdatedAt(new Date());
        bargainRecordMapper.insert(req);

        resultData.setValue(req.getId());
        return resultData;
    }

    @Override
    public ResultData<BasePageResp<BargainRecordVO>> getBargainRecordPage(PageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        req.setUserId(user.getId());

        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BargainRecordVO> list = bargainRecordMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Spu> spuMap = daoService.getSpuMap(list.stream().map(BargainRecordVO::getSpuId).collect(Collectors.toList()));
            Map<Long, Sku> skuMap = daoService.getSkuMap(list.stream().map(BargainRecordVO::getSkuId).collect(Collectors.toList()));

            List<BargainActivity> activityList = bargainActivityMapper.findAllByIds(list.stream().map(BargainRecordVO::getActivityId).collect(Collectors.toList()));

            Map<Long, BargainActivity> activityMap = new HashMap<>();
            activityList.stream().forEach(item -> activityMap.put(item.getId(), item));

            list.stream().forEach(item -> {
                item.setMainImage(spuMap.get(item.getSpuId()).getMainImage());
                item.setSpuName(spuMap.get(item.getSpuId()).getName());
                item.setSkuPrice(skuMap.get(item.getSkuId()).getPrice());
                item.setSpecValues(skuMap.get(item.getSkuId()).getSpecValues());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BargainRecordVO> getBargainRecordDetail(User user, Long id) {
        BargainRecordVO vo = new BargainRecordVO();

        BargainRecord bargainRecord = bargainRecordMapper.selectByPrimaryKey(id);
        BargainActivity bargainActivity = bargainActivityMapper.selectByPrimaryKey(bargainRecord.getActivityId());

        BeanUtils.copyProperties(bargainRecord, vo);

        Spu spu = spuMapper.selectByPrimaryKey(bargainRecord.getSpuId());
        Sku sku = skuMapper.selectByPrimaryKey(bargainRecord.getSkuId());
        User owner = userMapper.selectByPrimaryKey(bargainRecord.getUserId());

        if (user != null && !bargainRecord.getUserId().equals(user.getId())) {
            vo.setHasBargain(bargainDetailMapper.findOneByBargainRecordIdAndUserId(id, user.getId()) != null);
        }

        vo.setMainImage(spu.getMainImage());
        vo.setSpuName(spu.getName());
        vo.setSpecValues(sku.getSpecValues());
        vo.setAvatar(owner.getAvatar());
        vo.setNickname(owner.getNickname());
        vo.setSkuPrice(sku.getPrice());
        vo.setValidTime(bargainActivity.getValidTime());
        vo.setSpuType(spu.getType());

        return new ResultData<>(vo);
    }

    @Override
    public ResultData<BasePageResp<BargainDetailVO>> getBargainDetailPage(PageReq req) {
        if (req.getRelateId() == null) {
            req.setRelateId(0L);
        }

        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<BargainDetailVO> list = bargainDetailMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(BargainDetailVO::getUserId).collect(Collectors.toList()));

            list.stream().forEach(item -> {
                item.setAvatar(userMap.get(item.getUserId()).getAvatar());
                item.setNickname(userMap.get(item.getUserId()).getNickname());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BigDecimal> createBargainDetail(BargainDetail req) {

        ResultData<BigDecimal> resultData = new ResultData();

        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        BargainRecord bargainRecord = bargainRecordMapper.selectByPrimaryKey(req.getBargainRecordId());
        BargainActivity bargainActivity = bargainActivityMapper.selectByPrimaryKey(bargainRecord.getActivityId());
        List<BigDecimal> bigDecimalList = JSON.parseArray(bargainRecord.getFeature(), BigDecimal.class);

        // 判断是否已经砍过
        BargainDetail bargainDetail = bargainDetailMapper.findOneByUserIdAndActivityId(user.getId(), bargainRecord.getActivityId());

        if (bargainRecord.getUserId().equals(user.getId())) {
            resultData.setResultCode(ResultCode.FAIL);
            return resultData;
        }

        if (bargainDetail != null) {
            resultData.setResultCode(ResultCode.HAS_BEEN_BARGAIN);
            return resultData;
        }

        if (ToggleEnum.OFF.getStatus().equals(bargainActivity.getStatus())) {
            resultData.setResultCode(ResultCode.BARGAIN_OFF);
            return resultData;
        }

        // 判断是否已经过了砍价时间
        if (System.currentTimeMillis() > bargainRecord.getCreatedAt().getTime() + bargainActivity.getValidTime()) {
            resultData.setResultCode(ResultCode.OVER_BARGAIN_VALID_TIME);
            return resultData;
        }

        if (bargainRecord.getMaxHelperCount() <= bargainRecord.getHelperCount()) {
            resultData.setResultCode(ResultCode.BARGAIN_HELPER_OVER);
            return resultData;
        }

        req.setBargainAmount(bigDecimalList.get(bargainRecord.getHelperCount()));

        if (bargainRecord.getMaxBargainAmount().compareTo(bargainRecord.getBargainAmount().add(req.getBargainAmount())) < 0) {
            resultData.setResultCode(ResultCode.BARGAIN_HELPER_AMOUNT);
            return resultData;
        }

        req.setActivityId(bargainRecord.getActivityId());
        req.setUserId(user.getId());
        req.setCreatedAt(new Date());
        bargainDetailMapper.insert(req);

        // 更新砍价金额
        bargainRecord.setHelperCount(bargainRecord.getHelperCount() + 1);
        bargainRecord.setBargainAmount(bargainRecord.getBargainAmount().add(req.getBargainAmount()));
        bargainRecord.setUpdatedAt(new Date());
        bargainRecordMapper.updateByPrimaryKeySelective(bargainRecord);

        return new ResultData<>(req.getBargainAmount());
    }

    @Override
    public ResultData<BasePageResp<UserVoucherVO>> getUserVoucherPage(UserVoucherReq req) {
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setUserId(user.getId());
        List<UserVoucherVO> list = userVoucherMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            Map<Long, Shop> shopMap = daoService.getShopMap(list.stream().map(UserVoucherVO::getShopId).collect(Collectors.toList()));
            Map<Long, Spu> spuMap = daoService.getSpuMap(list.stream().map(UserVoucherVO::getSpuId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setShopName(shopMap.get(item.getShopId()).getShopName());
                item.setSpuImage(spuMap.get(item.getSpuId()).getMainImage());
                item.setSpuType(spuMap.get(item.getSpuId()).getType());
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BargainRecord> getBargainRecordBySkuId(User user, Long activityId, Long skuId) {
        return new ResultData<>(bargainRecordMapper.findOneByUserIdAndActivityIdAndSkuIdAndStatus(user.getId(), activityId, skuId, ToggleEnum.OFF.getStatus()));
    }

    @Override
    public ResultData<BasePageResp<LotteryOpportunityVO>> getLotteryOpportunityPage(LotteryOpportunityPageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setUserId(user.getId());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<LotteryOpportunityVO> list = lotteryOpportunityMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }
}